`timescale 1ns / 1ps
`include "param.v"  


module ALU (
    input wire [31:0] rd1,
    input wire [31:0] pc,
    input wire [31:0] rd2,
    input wire [31:0] imm,//连接SEXT.ext,立即数
    input wire alub_sel,//二选一多路选择集成在ALU里面
    input wire alua_sel,//0代表rd1,1代表auipc里的pc
    input wire [4:0] alu_op, //4位的alu_sel
    output reg [31:0] ALU_C,//问一下老师这里output用reg还是wire，如果用wire，那就另声明一个result reg变量
    output reg [1:0] ALU_f
);

reg [31:0] data1;
reg [31:0] data2;
//ALU进来时候的多路选择逻辑
always @(*) begin
     //选择data1
    if(alua_sel == 0)begin
        data1 = rd1;
    end
    else if(alua_sel == 1)begin
        data1 = pc;
    end
end

always @(*) begin
    //选择data2
    if(alub_sel == 0)begin
        data2 = rd2;
    end
    else if(alub_sel == 1)begin
        data2 = imm;
    end
end



reg [4:0]shiftnum;
always @(*) begin
    shiftnum = data2[4:0];
end

//无符号标记
reg unsignted =0;


//计算逻辑
reg [31:0] tempResult=0;
always @(*) begin
    case(alu_op)
        `ALU_ADD : ALU_C = data1 + data2;
        `ALU_SUB : ALU_C = data1 - data2;
        `ALU_AND : ALU_C = data1 & data2;
        `ALU_OR : ALU_C = data1 | data2;

        `ALU_XOR : ALU_C = data1 ^ data2;

        `ALU_SLL :ALU_C = data1 << shiftnum;
        `ALU_SRL : ALU_C = data1 >> shiftnum;
        `ALU_SRA : ALU_C = ($signed(data1)) >>> data2[4:0];//这一行是网上找的
        `ALU_BEQ :ALU_C = data1 - data2;
        `ALU_BNE :ALU_C = data1 - data2;
        `ALU_BLT :ALU_C = data1 - data2;
        `ALU_BGE :ALU_C = data1 - data2;
        `ALU_JALR :ALU_C = data1 + data2;
        `ALU_SLT : begin
            if(data1[31]==0 &&data2[31]==1)begin
                ALU_C = 0;//正数肯定 not less than 负数
            end
            else if(data1 == 'h8000_0000)begin
                ALU_C = 1; //data1 是最小负数，less than anthing
            end
            else begin
                tempResult = data1 - data2;
                if(tempResult[31]==1) ALU_C = 1;//less than
                else ALU_C = 0;
            end
        end
        `ALU_SLTU:begin
            if(data1 < data2) ALU_C = 1;
            else ALU_C = 0;
        end
        default : ALU_C = 0;
    endcase
end

//分支跳转判断
    always @(*) begin
        if(alu_op == `ALU_BLTU)begin
            if(data1 < data2) ALU_f = 2'b01;//lessthan
            else ALU_f = 2'b00;//ge
        end
        else if(alu_op == `ALU_BGEU)begin
            if(data1 < data2) ALU_f = 2'b01;//less than
            else ALU_f = 2'b00;//ge
        end
        else begin
            if(data1 - data2 ==0)begin
            ALU_f = 2'b10; //equal
        end
        else if(ALU_C[31]==0)begin
            ALU_f = 2'b00; //ge
        end
        else if(ALU_C[31]==1)begin
            ALU_f = 2'b01; //less than
        end
        else begin ALU_f = 2'b11; end//invalid
        end



    end
endmodule